// -*- coding: utf-8 -*-
/*
author: zengbin93
email: zeng_bin8888@163.com
create_dt: 2022/12/16 19:37
describe: 回测分析相关功能
*/

use crate::svc::base::{DataFrame, StyleConfig};
use serde_json::Value;
use std::collections::HashMap;

/// 显示权重分布
pub fn show_weight_distribution(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("标的", crate::svc::base::DataType::String, false);
    result.add_column("权重", crate::svc::base::DataType::Number, true);
    result.add_column("累计权重", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示权重回测
pub fn show_weight_backtest(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("日期", crate::svc::base::DataType::String, false);
    result.add_column("组合收益", crate::svc::base::DataType::Number, true);
    result.add_column("基准收益", crate::svc::base::DataType::Number, true);
    result.add_column("超额收益", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示持仓回测
pub fn show_holds_backtest(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("日期", crate::svc::base::DataType::String, false);
    result.add_column("持仓数量", crate::svc::base::DataType::Number, false);
    result.add_column("换手率", crate::svc::base::DataType::Number, true);
    result.add_column("平均持仓时间", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示按方向止损
pub fn show_stoploss_by_direction(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("方向", crate::svc::base::DataType::String, false);
    result.add_column("止损次数", crate::svc::base::DataType::Number, false);
    result.add_column("止损比例", crate::svc::base::DataType::Number, true);
    result.add_column("平均止损幅度", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示按阈值回测
pub fn show_backtest_by_thresholds(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("阈值", crate::svc::base::DataType::Number, false);
    result.add_column("信号数量", crate::svc::base::DataType::Number, false);
    result.add_column("胜率", crate::svc::base::DataType::Number, true);
    result.add_column("平均收益", crate::svc::base::DataType::Number, true);
    result.add_column("夏普比率", crate::svc::base::DataType::Number, true);
    
    result
}

/// 显示年度回测
pub fn show_yearly_backtest(df: &DataFrame, config: Option<&StyleConfig>) -> DataFrame {
    let config = config.unwrap_or(&StyleConfig::default());
    
    let mut result = DataFrame::new();
    result.add_column("年份", crate::svc::base::DataType::String, false);
    result.add_column("年化收益", crate::svc::base::DataType::Number, true);
    result.add_column("年化波动率", crate::svc::base::DataType::Number, true);
    result.add_column("夏普比率", crate::svc::base::DataType::Number, true);
    result.add_column("最大回撤", crate::svc::base::DataType::Number, true);
    
    result
}

/// 计算回测统计指标
pub fn calculate_backtest_stats(returns: &[f64], benchmark_returns: &[f64]) -> HashMap<String, f64> {
    let mut stats = HashMap::new();
    
    if returns.is_empty() {
        return stats;
    }
    
    // 计算基本统计指标
    let total_return = returns.iter().fold(1.0, |acc, &ret| acc * (1.0 + ret)) - 1.0;
    let annualized_return = calculate_annualized_return(returns, 252.0);
    let volatility = calculate_volatility(returns);
    let sharpe_ratio = if volatility > 0.0 {
        annualized_return / volatility
    } else {
        0.0
    };
    let max_drawdown = calculate_max_drawdown_from_returns(returns);
    let calmar_ratio = if max_drawdown > 0.0 {
        annualized_return / max_drawdown
    } else {
        0.0
    };
    
    // 计算胜率
    let win_count = returns.iter().filter(|&&r| r > 0.0).count();
    let win_rate = win_count as f64 / returns.len() as f64;
    
    // 计算盈亏比
    let avg_win = returns.iter().filter(|&&r| r > 0.0).sum::<f64>() / win_count.max(1) as f64;
    let avg_loss = returns.iter().filter(|&&r| r < 0.0).sum::<f64>() / (returns.len() - win_count).max(1) as f64;
    let profit_loss_ratio = if avg_loss.abs() > 0.0 {
        avg_win / avg_loss.abs()
    } else {
        0.0
    };
    
    // 计算超额收益
    let excess_returns: Vec<f64> = returns.iter().zip(benchmark_returns.iter())
        .map(|(r, br)| r - br)
        .collect();
    let excess_return = excess_returns.iter().sum::<f64>();
    let tracking_error = calculate_volatility(&excess_returns);
    let information_ratio = if tracking_error > 0.0 {
        excess_return / tracking_error
    } else {
        0.0
    };
    
    stats.insert("总收益".to_string(), total_return);
    stats.insert("年化收益".to_string(), annualized_return);
    stats.insert("年化波动率".to_string(), volatility);
    stats.insert("夏普比率".to_string(), sharpe_ratio);
    stats.insert("最大回撤".to_string(), max_drawdown);
    stats.insert("卡玛比率".to_string(), calmar_ratio);
    stats.insert("胜率".to_string(), win_rate);
    stats.insert("盈亏比".to_string(), profit_loss_ratio);
    stats.insert("超额收益".to_string(), excess_return);
    stats.insert("信息比率".to_string(), information_ratio);
    
    stats
}

/// 计算年化收益率
fn calculate_annualized_return(returns: &[f64], periods_per_year: f64) -> f64 {
    if returns.is_empty() {
        return 0.0;
    }
    
    let total_return = returns.iter().fold(1.0, |acc, &ret| acc * (1.0 + ret)) - 1.0;
    let num_periods = returns.len() as f64;
    
    if num_periods > 0.0 {
        (1.0 + total_return).powf(periods_per_year / num_periods) - 1.0
    } else {
        0.0
    }
}

/// 计算波动率
fn calculate_volatility(returns: &[f64]) -> f64 {
    if returns.is_empty() {
        return 0.0;
    }
    
    let mean_return = returns.iter().sum::<f64>() / returns.len() as f64;
    let variance = returns.iter()
        .map(|r| (r - mean_return).powi(2))
        .sum::<f64>() / returns.len() as f64;
    
    variance.sqrt()
}

/// 从收益率计算最大回撤
fn calculate_max_drawdown_from_returns(returns: &[f64]) -> f64 {
    if returns.is_empty() {
        return 0.0;
    }
    
    let mut cumulative = vec![1.0];
    for &ret in returns {
        let last_value = cumulative.last().unwrap();
        cumulative.push(last_value * (1.0 + ret));
    }
    
    let mut max_drawdown = 0.0;
    let mut peak = cumulative[0];
    
    for &value in &cumulative {
        if value > peak {
            peak = value;
        }
        
        let drawdown = (peak - value) / peak;
        if drawdown > max_drawdown {
            max_drawdown = drawdown;
        }
    }
    
    max_drawdown
}

/// 计算换手率
pub fn calculate_turnover_rate(weights: &[Vec<f64>]) -> Vec<f64> {
    if weights.len() < 2 {
        return vec![];
    }
    
    let mut turnover_rates = Vec::new();
    
    for i in 1..weights.len() {
        let prev_weights = &weights[i - 1];
        let curr_weights = &weights[i];
        
        if prev_weights.len() == curr_weights.len() {
            let turnover = prev_weights.iter().zip(curr_weights.iter())
                .map(|(prev, curr)| (prev - curr).abs())
                .sum::<f64>() / 2.0;
            turnover_rates.push(turnover);
        }
    }
    
    turnover_rates
}

/// 计算持仓时间
pub fn calculate_holding_periods(positions: &[Vec<String>]) -> Vec<f64> {
    if positions.is_empty() {
        return vec![];
    }
    
    let mut holding_periods = Vec::new();
    let mut symbol_holdings: HashMap<String, usize> = HashMap::new();
    
    for (period, position) in positions.iter().enumerate() {
        for symbol in position {
            if let Some(&start_period) = symbol_holdings.get(symbol) {
                let holding_period = period - start_period;
                holding_periods.push(holding_period as f64);
            } else {
                symbol_holdings.insert(symbol.clone(), period);
            }
        }
    }
    
    holding_periods
} 